]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
st-texture-cache: Add texture-file-changed signal
authorFlorian Müllner <fmuellner@gnome.org>
Thu, 20 Sep 2012 19:42:52 +0000 (21:42 +0200)
committerFlorian Müllner <fmuellner@gnome.org>
Wed, 17 Oct 2012 21:25:56 +0000 (23:25 +0200)
For textures loaded from files, the cache might hide image changes
by keeping the data of a previous version around indefinitely. For
instance AccountsService will notify of avatar changes, but as new
image is copied over the old one, we will continue to use the old
image data.
Install a file monitor for each file resource we load and clear
the corresponding data from the cache on changes, emitting the
new StTextureCache::texture-file-changed signal.

https://bugzilla.gnome.org/show_bug.cgi?id=679268

src/st/st-texture-cache.c

index 0508006fd9a343fb624f07d815e1e54cf8405926..2ba0f8e1bd1ef321df43fdf09347db33746583d7 100644 (file)
@@ -42,6 +42,9 @@ struct _StTextureCachePrivate
 
   /* Presently this is used to de-duplicate requests for GIcons and async URIs. */
   GHashTable *outstanding_requests; /* char * -> AsyncTextureLoadData * */
+
+  /* File monitors to evict cache data on changes */
+  GHashTable *file_monitors; /* char * -> GFileMonitor * */
 };
 
 static void st_texture_cache_dispose (GObject *object);
@@ -50,6 +53,7 @@ static void st_texture_cache_finalize (GObject *object);
 enum
 {
   ICON_THEME_CHANGED,
+  TEXTURE_FILE_CHANGED,
 
   LAST_SIGNAL
 };
@@ -92,6 +96,14 @@ st_texture_cache_class_init (StTextureCacheClass *klass)
                   0, /* no default handler slot */
                   NULL, NULL, NULL,
                   G_TYPE_NONE, 0);
+
+  signals[TEXTURE_FILE_CHANGED] =
+    g_signal_new ("texture-file-changed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, /* no default handler slot */
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 1, G_TYPE_STRING);
 }
 
 /**
@@ -164,6 +176,9 @@ st_texture_cache_init (StTextureCache *self)
                                                    g_free, cogl_handle_unref);
   self->priv->outstanding_requests = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                             g_free, NULL);
+  self->priv->file_monitors = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                     g_object_unref, g_object_unref);
+
 }
 
 static void
@@ -179,13 +194,9 @@ st_texture_cache_dispose (GObject *object)
       self->priv->icon_theme = NULL;
     }
 
-  if (self->priv->keyed_cache)
-    g_hash_table_destroy (self->priv->keyed_cache);
-  self->priv->keyed_cache = NULL;
-
-  if (self->priv->outstanding_requests)
-    g_hash_table_destroy (self->priv->outstanding_requests);
-  self->priv->outstanding_requests = NULL;
+  g_clear_pointer (&self->priv->keyed_cache, g_hash_table_destroy);
+  g_clear_pointer (&self->priv->outstanding_requests, g_hash_table_destroy);
+  g_clear_pointer (&self->priv->file_monitors, g_hash_table_destroy);
 
   G_OBJECT_CLASS (st_texture_cache_parent_class)->dispose (object);
 }
@@ -1039,6 +1050,52 @@ load_from_pixbuf (GdkPixbuf *pixbuf)
   return CLUTTER_ACTOR (texture);
 }
 
+static void
+file_changed_cb (GFileMonitor      *monitor,
+                 GFile             *file,
+                 GFile             *other,
+                 GFileMonitorEvent  event_type,
+                 gpointer           user_data)
+{
+  StTextureCache *cache = user_data;
+  char *uri, *key;
+
+  if (event_type != G_FILE_MONITOR_EVENT_CHANGED)
+    return;
+
+  uri = g_file_get_uri (file);
+
+  key = g_strconcat (CACHE_PREFIX_URI, uri, NULL);
+  g_hash_table_remove (cache->priv->keyed_cache, key);
+  g_free (key);
+
+  key = g_strconcat (CACHE_PREFIX_URI_FOR_CAIRO, uri, NULL);
+  g_hash_table_remove (cache->priv->keyed_cache, key);
+  g_free (key);
+
+  g_signal_emit (cache, signals[TEXTURE_FILE_CHANGED], 0, uri);
+
+  g_free (uri);
+}
+
+static void
+ensure_monitor_for_uri (StTextureCache *cache,
+                        const gchar    *uri)
+{
+  StTextureCachePrivate *priv = cache->priv;
+  GFile *file = g_file_new_for_uri (uri);
+
+  if (g_hash_table_lookup (priv->file_monitors, uri) == NULL)
+    {
+      GFileMonitor *monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE,
+                                                   NULL, NULL);
+      g_signal_connect (monitor, "changed",
+                        G_CALLBACK (file_changed_cb), cache);
+      g_hash_table_insert (priv->file_monitors, g_strdup (uri), monitor);
+    }
+  g_object_unref (file);
+}
+
 typedef struct {
   gchar *path;
   gint   grid_width, grid_height;
@@ -1211,6 +1268,8 @@ st_texture_cache_load_uri_async (StTextureCache *cache,
       load_texture_async (cache, request);
     }
 
+  ensure_monitor_for_uri (cache, uri);
+
   return CLUTTER_ACTOR (texture);
 }
 
@@ -1248,6 +1307,8 @@ st_texture_cache_load_uri_sync_to_cogl_texture (StTextureCache *cache,
   else
     cogl_handle_ref (texdata);
 
+  ensure_monitor_for_uri (cache, uri);
+
 out:
   g_free (key);
   return texdata;
@@ -1287,6 +1348,8 @@ st_texture_cache_load_uri_sync_to_cairo_surface (StTextureCache        *cache,
   else
     cairo_surface_reference (surface);
 
+  ensure_monitor_for_uri (cache, uri);
+
 out:
   g_free (key);
   return surface;